//Class for an entity-
//anything that moves or needs collisions (ie the player or a rock)

#include "Entity.h"
//list of entities and collision entities
std::vector<Entity*>     Entity::EntityList;
std::vector<EntityCol> EntityCol::EntityColList;

EntityCol::EntityCol() {
    this->Entity1 = NULL;
    this->Entity2 = NULL;
}

//default constructor
Entity::Entity() {

    Surf_Entity = NULL;

    X = 0;
    Y = 0;

    Width     = 0;
    Height     = 0;

    MoveLeft  = false;
    MoveRight = false;
    MoveDown = false;
    MoveUp = false;

    Type =     ENTITY_TYPE_GENERIC;

    // Flags = ENTITY_FLAG_GRAVITY;

    SpeedX = 0;
    SpeedY = 0;

    CurrentFrameCol = 0;
    CurrentFrameRow = 0;

    Col_X = 0;
    Col_Y = 0;

    Col_Width  = 0;
    Col_Height = 0;
}

//default destructor
Entity::~Entity() {
}

//OnLoad
bool Entity::OnLoad(char* File, int Width, int Height, int MaxFrames) {
	if((Surf_Entity = Surface::OnLoad(File)) == NULL) {
		return false;
	}

	 //Surface::Transparent(Surf_Entity, 255, 0, 255);//Not needed -Andro

	this->Width = Width;
	this->Height = Height;

	Anim_Control.MaxFrames = MaxFrames;

    return true;
}

//OnLoop
void Entity::OnLoop() {
    //not moving
    if(MoveLeft == false && MoveRight == false && MoveDown == false && MoveUp == false) {
        StopMove();
    }
    if(MoveLeft) {
        SpeedX = -5;
        SpeedY = 0;
    }
    else if(MoveRight) {
        SpeedX = 5;
        SpeedY = 0;
    }
    else if(MoveDown) {
        SpeedY = 5;
        SpeedX = 0;
    }
    else if(MoveUp) {
        SpeedY = -5;
        SpeedX = 0;
    }

    OnAnimate();
    OnMove(SpeedX, SpeedY);
}
//OnRender
void Entity::OnRender(SDL_Surface* Surf_Display) {
    if(Surf_Entity == NULL || Surf_Display == NULL) return;

    Surface::OnDraw(Surf_Display, Surf_Entity, X - Camera::CameraControl.GetX(), Y - Camera::CameraControl.GetY(), CurrentFrameCol * Width, (CurrentFrameRow + Anim_Control.GetCurrentFrame()) * Height, Width, Height);
}
//OnCleanup
void Entity::OnCleanup() {
    if(Surf_Entity) {
        SDL_FreeSurface(Surf_Entity);
    }

    Surf_Entity = NULL;
}

//OnAnimate
void Entity::OnAnimate() {
    if(MoveLeft) {
        CurrentFrameCol = 1;
        CurrentFrameRow = 1;
    }else

    if(MoveRight) {
        CurrentFrameCol = 1;
        CurrentFrameRow = 2;
    }

    if(MoveDown) {
        CurrentFrameCol = 1;
        CurrentFrameRow = 0;
        }

    if(MoveUp) {
        CurrentFrameCol = 1;
        CurrentFrameRow = 3;
        }

 //   Anim_Control.OnAnimate();
}

//OnCollision
bool Entity::OnCollision(Entity* Entity) {
}

//OnMove
void Entity::OnMove(float MoveX, float MoveY) {
    if(MoveX == 0 && MoveY == 0) return;

    double NewX = 0;
    double NewY = 0;

    MoveX *= FPS::FPSControl.GetSpeedFactor();
    MoveY *= FPS::FPSControl.GetSpeedFactor();

    if(MoveX != 0) {
        if(MoveX >= 0)     NewX =  FPS::FPSControl.GetSpeedFactor();
        else             NewX = -FPS::FPSControl.GetSpeedFactor();
    }

    if(MoveY != 0) {
        if(MoveY >= 0)     NewY =  FPS::FPSControl.GetSpeedFactor();
        else             NewY = -FPS::FPSControl.GetSpeedFactor();
    }

    while(true) {
        if(Flags) {
            PosValid((int)(X + NewX), (int)(Y + NewY)); //We don't care about collisions, but we need to send events to other entities

            X += NewX;
            Y += NewY;
        }else{
            if(PosValid((int)(X + NewX), (int)(Y))) {
                X += NewX;
            }else{
                SpeedX = 0;
            }

            if(PosValid((int)(X), (int)(Y + NewY))) {
                Y += NewY;
            }else{
                SpeedY = 0;
            }
        }

        MoveX += -NewX;
        MoveY += -NewY;

        if(NewX > 0 && MoveX <= 0) NewX = 0;
        if(NewX < 0 && MoveX >= 0) NewX = 0;

        if(NewY > 0 && MoveY <= 0) NewY = 0;
        if(NewY < 0 && MoveY >= 0) NewY = 0;

        if(MoveX == 0) NewX = 0;
        if(MoveY == 0) NewY = 0;

        if(MoveX == 0 && MoveY     == 0)     break;
        if(NewX  == 0 && NewY     == 0)     break;
    }
}

//StopMove
void Entity::StopMove() {

   //if(SpeedX != 0 || SpeedY !=0){ //Don't need this - Andro
        SpeedX = 0;
        SpeedY = 0;
        //}
}

//Collides
bool Entity::Collides(int oX, int oY, int oW, int oH) {
    int left1, left2;
    int right1, right2;
    int top1, top2;
    int bottom1, bottom2;

    int tX = (int)X + Col_X;
    int tY = (int)Y + Col_Y;

    left1 = tX;
    left2 = oX;

    right1 = left1 + Width - 1 - Col_Width;
    right2 = oX + oW - 1;

    top1 = tY;
    top2 = oY;

    bottom1 = top1 + Height - 1 - Col_Height;
    bottom2 = oY + oH - 1;


    if (bottom1 < top2) return false;
    if (top1 > bottom2) return false;

    if (right1 < left2) return false;
    if (left1 > right2) return false;

    return true;
}

//PosValid
bool Entity::PosValid(int NewX, int NewY) {
    bool Return = true;

    int StartX     = (NewX + Col_X) / TILE_SIZE;
    int StartY     = (NewY + Col_Y) / TILE_SIZE;

    int EndX    = ((NewX + Col_X) + Width - Col_Width - 1)         / TILE_SIZE;
    int EndY    = ((NewY + Col_Y) + Height - Col_Height - 1)    / TILE_SIZE;

    for(int iY = StartY;iY <= EndY;iY++) {
        for(int iX = StartX;iX <= EndX;iX++) {
            Tile* Tile = Area::AreaControl.GetTile(iX * TILE_SIZE, iY * TILE_SIZE);

            if(PosValidTile(Tile) == false) {
                Return = false;
            }
        }
    }

    if(Flags & ENTITY_FLAG_MAPONLY) {
    }else{
        for(int i = 0;i < EntityList.size();i++) {
            if(PosValidEntity(EntityList[i], NewX, NewY) == false) {
                Return = false;
            }
        }
    }

    return Return;
}

//PosValidTile
bool Entity::PosValidTile(Tile* Tile) {
    if(Tile == NULL) {
        return true;
    }

    if(Tile->TypeID == TILE_TYPE_BLOCK) {
        return false;
    }

    return true;
}

//PosValidEntity
bool Entity::PosValidEntity(Entity* Entity, int NewX, int NewY) {
    if(this != Entity && Entity != NULL  &&
        Entity->Flags ^ ENTITY_FLAG_MAPONLY &&
        Entity->Collides(NewX + Col_X, NewY + Col_Y, Width - Col_Width - 1, Height - Col_Height - 1) == true) {

        EntityCol EntityCol;

        EntityCol.Entity1 = this;
        EntityCol.Entity2 = Entity;

        EntityCol::EntityColList.push_back(EntityCol);

        return false;
    }

    return true;
}
